package com.fancy.middleware.netty.config;

import com.fancy.middleware.common.annotation.V1Server;
import com.fancy.middleware.common.annotation.V2Server;
import com.fancy.middleware.common.annotation.V3Server;
import com.fancy.middleware.netty.handler.codec.HalfAndGluedFrameDecoder;
import com.fancy.middleware.netty.handler.timeout.IdleStateEventHandler;
import com.fancy.middleware.netty.properties.NettyProperties;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelDuplexHandler;
import io.netty.channel.ChannelInboundHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleStateHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ServerBootstrap.class)
@EnableConfigurationProperties(NettyProperties.class)
@Import({NioNettyConfiguration.class, EpollNettyConfiguration.class, NettyCommonConfiguration.class})
public class NettyAutoConfiguration {
    @Autowired
    @Qualifier("bossEventLoopGroup")
    private EventLoopGroup bossEventLoopGroup;

    @Autowired
    @Qualifier("workerEventLoopGroup")
    private EventLoopGroup workerEventLoopGroup;

    @Autowired
    @Qualifier("defaultEventLoopGroup")
    private EventLoopGroup defaultEventLoopGroup;

    @Autowired
    private Class channelClazz;

    @Autowired
    @Qualifier("cacheFrameHandler")
    private ChannelInboundHandler cacheFrameHandler;

    @Autowired
    @Qualifier("protocolCodecSharable")
    private ChannelDuplexHandler protocolCodecSharable;

    @Bean
    @ConditionalOnMissingBean
    @V1Server
    public ServerBootstrap v1ServerBootstrap(){
        return new ServerBootstrap()
                .group(bossEventLoopGroup, workerEventLoopGroup)
                .channel(channelClazz)
                // child 执行器 用于处理ServerSocketChannel 获取到的 SocketChannel
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    // 初始化 连接建立时候执行
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 粘包和半包处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new HalfAndGluedFrameDecoder());
                        // TODO modify loggingHandler   先处理粘包和半包 再日志记录  ??
                        ch.pipeline().addLast(new LoggingHandler());
                        // 编码解码器
                        ch.pipeline().addLast(defaultEventLoopGroup, protocolCodecSharable);
                        // TODO add TCP连接假死处理器 数据需要做成配置
                        // 闲置状态处理器 IdleStateHandler的当前设计不可重用。您必须创建新的IdleStateHandler并将旧的替换为新的实例。 客户端可使用心跳
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateHandler(5, 0, 0));
//                         IdleState 事件处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateEventHandler());
                        // cache
                        ch.pipeline().addLast(defaultEventLoopGroup, cacheFrameHandler);
                    }
                });
    }

    @Bean
    @ConditionalOnMissingBean
    @V2Server
    public ServerBootstrap v2ServerBootstrap() {
        return new ServerBootstrap()
                .group(bossEventLoopGroup, workerEventLoopGroup)
                .channel(channelClazz)
                // child 执行器 用于处理ServerSocketChannel 获取到的 SocketChannel
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    // 初始化 连接建立时候执行
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 粘包和半包处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new HalfAndGluedFrameDecoder());
                        // TODO modify loggingHandler   先处理粘包和半包 再日志记录  ??
                        ch.pipeline().addLast(new LoggingHandler());
                        // 编码解码器
                        ch.pipeline().addLast(defaultEventLoopGroup, protocolCodecSharable);
                        // TODO add TCP连接假死处理器 数据需要做成配置
                        // 闲置状态处理器 IdleStateHandler的当前设计不可重用。您必须创建新的IdleStateHandler并将旧的替换为新的实例。 客户端可使用心跳
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateHandler(5, 0, 0));
//                         IdleState 事件处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateEventHandler());
                        // cache
                        ch.pipeline().addLast(defaultEventLoopGroup, cacheFrameHandler);
                    }
                });
    }

    @Bean
    @ConditionalOnMissingBean
    @V3Server
    public ServerBootstrap v3ServerBootstrap(){
        return new ServerBootstrap()
                .group(bossEventLoopGroup, workerEventLoopGroup)
                .channel(channelClazz)
                // child 执行器 用于处理ServerSocketChannel 获取到的 SocketChannel
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    // 初始化 连接建立时候执行
                    protected void initChannel(SocketChannel ch) throws Exception {
                        // 粘包和半包处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new HalfAndGluedFrameDecoder());
                        // TODO modify loggingHandler   先处理粘包和半包 再日志记录  ??
                        ch.pipeline().addLast(new LoggingHandler());
                        // 编码解码器
                        ch.pipeline().addLast(defaultEventLoopGroup, protocolCodecSharable);
                        // TODO add TCP连接假死处理器 数据需要做成配置
                        // 闲置状态处理器 IdleStateHandler的当前设计不可重用。您必须创建新的IdleStateHandler并将旧的替换为新的实例。 客户端可使用心跳
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateHandler(5, 0, 0));
//                         IdleState 事件处理
                        ch.pipeline().addLast(defaultEventLoopGroup, new IdleStateEventHandler());
                        // cache
                        ch.pipeline().addLast(defaultEventLoopGroup, cacheFrameHandler);
                    }
                });
    }
}
